/*
 * Copyright 2011-2012 by The Regents of the University of California Licensed
 * under the Apache License, Version 2.0 (the "License"); you may not use this
 * file except in compliance with the License. you may obtain a copy of the
 * License from
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package edu.ucsd.db.bassarisk.storage.loading;

import java.nio.ByteBuffer;

import edu.ucsd.db.bassarisk.data.values.IntType;
import edu.ucsd.db.bassarisk.storage.common.ColumnStore;

/**
 * Builds a very simple drawer index for a column of 32-bit integer values
 * arranged using a fixed-width card and fixed-width card indexing scheme.
 * 
 * What is indexed at the column level? 4 bytes - first value on card 8 bytes -
 * first index on card
 * 
 * What is in a drawer header?
 * 
 * All drawers # 2 bytes :: "drawer index version" determines type and version
 * This Drawer # 2 bytes :: number of values TOTAL 4 bytes
 * 
 * What is in a drawer index? 
 *   <li>4 bytes/card - first value on card 
 *   <li>0 bytes/card - first index on card (can be computed for fixed-width) 
 * TOTAL 4 bytes per card,
 * MAX 504 bytes = 2 cards less 8 bytes
 */
public class FixedLengthAscendingIntegerDrawerIndexer extends
    FixedLengthAscendingIntegerSegmentIndexer implements IDrawerIndexer<IntType> {

  private static final short drawerIndexVersion = 1;

  private static final int BYTES_PER_ENTRY = 4;
  private static final int BYTES_IN_HEADER = 4;

  public FixedLengthAscendingIntegerDrawerIndexer() {
    super();
    this.segmentMinValues = new int[ColumnStore.CARDS_IN_DRAWER];
    this.segmentValueCounts = new int[ColumnStore.CARDS_IN_DRAWER];
  }

  @Override
  protected int getBytesForHeader() {
    return BYTES_IN_HEADER;
  };

  @Override
  protected int getBytesPerEntry() {
    return BYTES_PER_ENTRY;
  };

  @Override
  public boolean indexCard(final ColumnSegmentInfo<IntType> cardInfo,
                           final boolean canIncreaseIndexSize) {
    // Becuase of the "fixed size" properties of this simple index, we can
    // safely ignore the canIncreaseIndexSize property.
    this.segmentMinValues[this.numIndexedSegments] =
        intManip.getIntegerValue(cardInfo.getFirstValue());
    this.segmentValueCounts[this.numIndexedSegments] =
        (int) cardInfo.getEntryCount();
    this.numIndexedSegments++;
    return true;
  }

  @Override
  protected void
      writeHeaderValues(final ByteBuffer drawer, final int headerEndOffset) {

    // position at start of header information
    drawer.position(headerEndOffset - 4);
    short totalValues = 0;
    for (int i = 0; i < this.numIndexedSegments; i++) {
      totalValues += this.segmentValueCounts[i];
      // all cards must be full except the last one.
      assert (this.segmentValueCounts[i] == 64 || (i + 1) == this.numIndexedSegments);
    }
    drawer.putShort(totalValues);
    drawer.putShort(FixedLengthAscendingIntegerDrawerIndexer.drawerIndexVersion);

  }

}
